﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

namespace ScanSystemLogForm
{
    ///  
    /// 系统信息类 - 获取CPU、内存、磁盘、进程信息 ,ip, DNS, 主机名
    ///  
    public class SystemInfo
    {
        private int m_ProcessorCount = 0;   //CPU个数 
        private PerformanceCounter pcCpuLoad;   //CPU计数器 
        private long m_PhysicalMemory = 0;   //物理内存 

        private const int GW_HWNDFIRST = 0;
        private const int GW_HWNDNEXT = 2;
        private const int GWL_STYLE = (-16);
        private const int WS_VISIBLE = 268435456;
        private const int WS_BORDER = 8388608;

        #region AIP声明 
        [DllImport("IpHlpApi.dll")]
        extern static public uint GetIfTable(byte[] pIfTable, ref uint pdwSize, bool bOrder);

        [DllImport("User32")]
        private extern static int GetWindow(int hWnd, int wCmd);

        [DllImport("User32")]
        private extern static int GetWindowLongA(int hWnd, int wIndx);

        [DllImport("user32.dll")]
        private static extern bool GetWindowText(int hWnd, StringBuilder title, int maxBufSize);

        [DllImport("user32", CharSet = CharSet.Auto)]
        private extern static int GetWindowTextLength(IntPtr hWnd);
        #endregion

        #region 构造函数 
        ///  
        /// 构造函数，初始化计数器等 
        ///  
        public SystemInfo()
        {
            //初始化CPU计数器 
            pcCpuLoad = new PerformanceCounter("Processor", "% Processor Time", "_Total");
            pcCpuLoad.MachineName = ".";
            pcCpuLoad.NextValue();

            //CPU个数 
            m_ProcessorCount = Environment.ProcessorCount;

            //获得物理内存 
            ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                if (mo["TotalPhysicalMemory"] != null)
                {
                    m_PhysicalMemory = long.Parse(mo["TotalPhysicalMemory"].ToString());
                }
            }
        }
        #endregion


        /// <summary> 
        /// 获取当前使用的IP 
        /// </summary> 
        /// <returns></returns> 
        public string GetLocalIP()
        {
            string result = RunApp("route", "print", true);
            Match m = Regex.Match(result, @"0.0.0.0\s+0.0.0.0\s+(\d+.\d+.\d+.\d+)\s+(\d+.\d+.\d+.\d+)");
            if (m.Success)
            {
                return m.Groups[2].Value;
            }
            else
            {
                try
                {
                    System.Net.Sockets.TcpClient c = new System.Net.Sockets.TcpClient();
                    c.Connect("www.baidu.com", 80);
                    string ip = ((System.Net.IPEndPoint)c.Client.LocalEndPoint).Address.ToString();
                    c.Close();
                    return ip;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }
        /// <summary> 
        /// 获取本机主DNS 
        /// </summary> 
        /// <returns></returns> 
        public string GetPrimaryDNS()
        {
            string result = RunApp("nslookup", "", true);
            Match m = Regex.Match(result, @"\d+\.\d+\.\d+\.\d+");
            if (m.Success)
            {
                return m.Value;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 使用ipconfig.exe读取ip信息
        /// </summary>
        private void GetIP()
        {
            Process cmd = new Process();
            cmd.StartInfo.FileName = "ipconfig.exe";//设置程序名 
            cmd.StartInfo.Arguments = "/all"; //参数 
                                              //重定向标准输出 
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.RedirectStandardInput = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.StartInfo.CreateNoWindow = true;//不显示窗口（控制台程序是黑屏） 
                                                //cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//暂时不明白什么意思 
                                                /* 
                                                收集一下 有备无患 
                                                关于:ProcessWindowStyle.Hidden隐藏后如何再显示？ 
                                                hwndWin32Host = Win32Native.FindWindow(null, win32Exinfo.windowsName); 
                                                Win32Native.ShowWindow(hwndWin32Host, 1); //先FindWindow找到窗口后再ShowWindow 
                                                */
            cmd.Start();
            string info = cmd.StandardOutput.ReadToEnd();   // 读取可上网的IP
            cmd.WaitForExit();
            cmd.Close();
        }

        /// <summary> 
        /// 运行一个控制台程序并返回其输出参数。 
        /// </summary> 
        /// <param name="filename">程序名</param> 
        /// <param name="arguments">输入参数</param> 
        /// <returns></returns> 
        public static string RunApp(string filename, string arguments, bool recordLog)
        {
            try
            {
                if (recordLog)
                {
                    Trace.WriteLine(filename + " " + arguments);
                }
                Process proc = new Process();
                proc.StartInfo.FileName = filename;
                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.Arguments = arguments;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.UseShellExecute = false;
                proc.Start();
                using (StreamReader sr = new StreamReader(proc.StandardOutput.BaseStream, Encoding.Default))
                {
                    //string txt = sr.ReadToEnd(); 
                    //sr.Close(); 
                    //if (recordLog) 
                    //{ 
                    // Trace.WriteLine(txt); 
                    //} 
                    //if (!proc.HasExited) 
                    //{ 
                    // proc.Kill(); 
                    //} 
                    //上面标记的是原文，下面是我自己调试错误后自行修改的 
                    Thread.Sleep(100);  //貌似调用系统的nslookup还未返回数据或者数据未编码完成，程序就已经跳过直接执行 
                                        //txt = sr.ReadToEnd()了，导致返回的数据为空，故睡眠令硬件反应 
                    if (!proc.HasExited)  //在无参数调用nslookup后，可以继续输入命令继续操作，如果进程未停止就直接执行 
                    {    //txt = sr.ReadToEnd()程序就在等待输入，而且又无法输入，直接掐住无法继续运行 
                        proc.Kill();
                    }
                    string txt = sr.ReadToEnd();
                    sr.Close();
                    if (recordLog)
                        Trace.WriteLine(txt);
                    return txt;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
                return ex.Message;
            }
        }

        /// <summary>
        /// 获取CPU个数 
        /// </summary>
        public int ProcessorCount
        {
            get
            {
                return m_ProcessorCount;
            }
        }

        /// <summary>
        /// 获取CPU占用率 
        /// </summary>
        public float CpuUsePercent
        {
            get
            {
                return pcCpuLoad.NextValue();
            }
        }

        /// <summary>
        /// 获取可用内存 
        /// </summary>
        public long MemoryAvailable
        {
            get
            {
                long availablebytes = 0;
                ManagementClass mos = new ManagementClass("Win32_OperatingSystem");
                foreach (ManagementObject mo in mos.GetInstances())
                {
                    if (mo["FreePhysicalMemory"] != null)
                    {
                        availablebytes = 1024 * long.Parse(mo["FreePhysicalMemory"].ToString());
                    }
                }
                return availablebytes;
            }
        }



        /// <summary>
        /// 获取物理内存 
        /// </summary>
        public long PhysicalMemory
        {
            get
            {
                return m_PhysicalMemory;
            }
        }


        #region 获得分区信息 
        /// <summary>
        /// 获取分区信息 
        /// </summary>
        /// <returns></returns>
        public List<DiskInfo> GetLogicalDisk()
        {
            List<DiskInfo> drives = new List<DiskInfo>();
            ManagementClass diskClass = new ManagementClass("Win32_LogicalDisk");
            ManagementObjectCollection disks = diskClass.GetInstances();
            foreach (ManagementObject disk in disks)
            {
                // DriveType.Fixed 为固定磁盘(硬盘) 
                if (int.Parse(disk["DriveType"].ToString()) == (int)DriveType.Fixed)
                {
                    drives.Add(new DiskInfo(disk["Name"].ToString(), Convert.ToInt64(disk["Size"]), Convert.ToInt64(disk["FreeSpace"])));
                }
            }
            return drives;
        }
        /// <summary>
        /// 获取特定分区信息 (盘符)
        /// </summary>
        /// <param name="DriverID"></param>
        /// <returns></returns>
        public List<DiskInfo> GetLogicalDrives(char DriverID)
        {
            List<DiskInfo> drives = new List<DiskInfo>();
            WqlObjectQuery wmiquery = new WqlObjectQuery("SELECT * FROM Win32_LogicalDisk WHERE DeviceID = ’" + DriverID + ":’");
            ManagementObjectSearcher wmifind = new ManagementObjectSearcher(wmiquery);
            foreach (ManagementObject disk in wmifind.Get())
            {
                if (int.Parse(disk["DriveType"].ToString()) == (int)DriveType.Fixed)
                {
                    drives.Add(new DiskInfo(disk["Name"].ToString(), Convert.ToInt64(disk["Size"]), Convert.ToInt64(disk["FreeSpace"])));
                }
            }
            return drives;
        }
        #endregion

        #region 获得进程列表 
        /// <summary>
        ///  获得进程列表 
        /// </summary>
        /// <returns></returns>
        public List<ProcessInfo> GetProcessInfo()
        {
            List<ProcessInfo> pInfo = new List<ProcessInfo>();
            Process[] processes = Process.GetProcesses();
            foreach (Process instance in processes)
            {
                try
                {
                    pInfo.Add(new ProcessInfo(instance.Id,
                        instance.ProcessName,
                        instance.TotalProcessorTime.TotalMilliseconds,
                        instance.WorkingSet64,
                        instance.MainModule.FileName));
                }
                catch { }
            }
            return pInfo;
        }

        /// <summary>
        /// 获得特定进程信息 (进程名称)
        /// </summary>
        /// <param name="ProcessName"></param>
        /// <returns></returns>
        public List<ProcessInfo> GetProcessInfo(string ProcessName)
        {
            List<ProcessInfo> pInfo = new List<ProcessInfo>();
            Process[] processes = Process.GetProcessesByName(ProcessName);
            foreach (Process instance in processes)
            {
                try
                {
                    pInfo.Add(new ProcessInfo(instance.Id,
                        instance.ProcessName,
                        instance.TotalProcessorTime.TotalMilliseconds,
                        instance.WorkingSet64,
                        instance.MainModule.FileName));
                }
                catch { }
            }
            return pInfo;
        }
        #endregion

        #region 结束指定进程 
        /// <summary>
        ///  结束指定进程 (进程的ProcessID)
        /// </summary>
        /// <param name="pid"></param>
        public static void EndProcess(int pid)
        {
            try
            {
                Process process = Process.GetProcessById(pid);
                process.Kill();
            }
            catch { }
        }
        #endregion


        #region 查找所有应用程序标题 
        /// <summary>
        /// 查找所有应用程序标题 (应用程序标题泛型集合)
        /// </summary>
        /// <param name="Handle"></param>
        /// <returns></returns>
        public static List<string> FindAllApps(int Handle)
        {
            List<string> Apps = new List<string>();

            int hwCurr;
            hwCurr = GetWindow(Handle, GW_HWNDFIRST);

            while (hwCurr > 0)
            {
                int IsTask = (WS_VISIBLE | WS_BORDER);
                int lngStyle = GetWindowLongA(hwCurr, GWL_STYLE);
                bool TaskWindow = ((lngStyle & IsTask) == IsTask);
                if (TaskWindow)
                {
                    int length = GetWindowTextLength(new IntPtr(hwCurr));
                    StringBuilder sb = new StringBuilder(2 * length + 1);
                    GetWindowText(hwCurr, sb, sb.Capacity);
                    string strTitle = sb.ToString();
                    if (!string.IsNullOrEmpty(strTitle))
                    {
                        Apps.Add(strTitle);
                    }
                }
                hwCurr = GetWindow(hwCurr, GW_HWNDNEXT);
            }

            return Apps;
        }
        #endregion
    }

    /// <summary>
    /// 硬盘信息
    /// </summary>
    public class DiskInfo
    {
        public string Name { get; set; }
        public long Size { get; set; }
        public long FreeSpace { get; set; }


        public DiskInfo(string name,long size, long freeSpace)
        {
            Name = name;
            Size = size;
            FreeSpace = freeSpace;
        }

        public DiskInfo() { }
    }

    /// <summary>
    /// 进程信息
    /// </summary>
    public class ProcessInfo
    {
        public int Id { get; set; }

        public string ProcessName { get; set; }

        /// <summary>
        /// 此进程的总的处理器时间, 毫秒
        /// </summary>
        public double TotalMilliseconds { get; set; }

        /// <summary>
        /// 此进程分配的内存大小,单位字节
        /// </summary>
        public long WorkingSet64 { get; set; }

        /// <summary>
        /// 获取该模块的完整路径
        /// </summary>
        public string FileName { get; set; }

        public ProcessInfo(int id,string processName,double totalMilliseconds,long workingSet64,string fileName)
        {
            Id = id;
            ProcessName = processName;
            TotalMilliseconds = totalMilliseconds;
            WorkingSet64 = workingSet64;
            FileName = fileName;
        }

        public ProcessInfo() { }
    }

}